<template>
  <div class="action-block" ref="box" :style="{
    width: `${actionWidth}px`,
    left: `${actionLeft}px`,
    top: `${blockData ? (blockData.top ? blockData.top + 'px' : props.defaultTop + 'px') : '0px'}`,
    height: `${defaultTimeBlockHeight}px`,
  }">
    <div class="action-box">
      <!--用于拉伸X 坐标，让他变长缩短-->
      <div class="left-box action" v-if="enableDragSide" @mousedown="onMouseLineDown($event, -1)"
        @contextmenu.prevent="() => { }"></div>

      <!--时间块的具体内容 拖拽事件-->
      <div class="action-content" @mousedown="enableDragFree ? onMouseFreeDown($event) : null">
        <slot></slot>
      </div>
      <!--用于拉伸X 坐标，让他变长缩短-->
      <div class="right-box action" v-if="enableDragSide" @mousedown="onMouseLineDown($event, 1)"
        @contextmenu.prevent="() => { }"></div>
    </div>
  </div>
</template>
<script setup>
import { getAbsTop } from "@/assets/js/util"
import { computed, ref, inject, nextTick } from "vue";

const myInject = inject('onActionBlockUp')

const scrollLeftRef = inject('scrollLeftRef')

const mousePosition = {
  left: 0,
  right: 0
}

let uniqueId = 0

const emit = defineEmits(['moveSideChange', 'moveSideDown', 'onActionBlockDown'])


const props = defineProps({
  // 操作的那个dom
  actionArea: {
    type: Object,
    default: () => { }
  },
  // 时间条间隔高度
  defaultTop: {
    type: Number,
    default: 10
  },
  // 时间条高度
  defaultTimeBlockHeight: {
    type: Number,
    default: 40
  },
  //时间块数据
  blockData: {
    type: Object,
    default: () => { }
  },
  // 行数据
  rowData: {
    type: Object,
    default: () => { }
  },
  // 所有数据
  ganttData: {
    type: Array,
    default: () => []
  },
  //在外头选择的时间
  choiceTime: {
    type: Array,
    default: () => []
  },
  //左右可拖拽
  enableDragSide: {
    type: Boolean,
    default: false
  },
  //是否允许自由拖拽，但是该组件的自由拖拽不进行真实交互，只是回调事件
  enableDragFree: {
    type: Boolean,
    default: false
  },
  //开始时间的字段
  startTimeCol: {
    type: String,
    default: 'startTime'
  },
  //结束时间的字段
  endTimeCol: {
    type: String,
    default: 'endTime'
  },
  // 比例伸缩
  scaleWidth: {
    type: Number,
    default: 1
  },
  // 时间条最小宽度
  actionBlockMinWidth: {
    type: Number,
    default: 50
  },
  // 时间条List  二维数组里时间条的字段
  timeBlockCol: {
    type: String,
    default: 'timeBlock'
  }
})
//时间块的宽度
const actionWidth = computed(() => {
  if (props.blockData) {

    const startTime = new Date(props.blockData[props.startTimeCol])

    const endTime = new Date(props.blockData[props.endTimeCol])

    //计算差值
    let diffTime = (endTime.getTime() - startTime.getTime()) / 1000 / 60
    return diffTime * props.scaleWidth
  }
  return 0
})
//时间块的左边偏移量
const actionLeft = computed(() => {
  if (props.blockData) {

    const limitTime = new Date(props.choiceTime[0])

    const startTime = new Date(props.blockData[props.startTimeCol])

    //计算时间块的左边距离甘特图边界的距离
    let diffTime = (startTime.getTime() - limitTime.getTime()) / 1000 / 60
    return diffTime * props.scaleWidth
  }
  return 0
})

/**
 * 时间块左右两边的可拖拽滑块 direction: -1 左边；1右边
 */
const onMouseLineDown = (e, direction) => {
  const startTimeDate = new Date(props.blockData[props.startTimeCol])

  const endTimeDate = new Date(props.blockData[props.endTimeCol])

  let startTime = startTimeDate.getTime()
  let endTime = endTimeDate.getTime()

  //可滚动区域
  let wordDom = props.actionArea

  emit('moveSideDown', props.blockData)

  const downScrollLeft = scrollLeftRef.value

  wordDom.onmousemove = (ee) => {

    const nowScrollLeft = scrollLeftRef.value
    // 用鼠标的位置减去鼠标相对元素的位置，得到元素的位置
    let v = ee.clientX - e.clientX + (nowScrollLeft - downScrollLeft);
    //v左边移动减少
    if (direction == -1) {

      //左边拉长是减少
      if (mousePosition.left < v) {
        //如果是缩短，那么就可以进行width不为-1的判断了
        if (actionWidth.value <= 0) {
          return
        }
      }

      //分钟赋值后，设置成new Date
      props.blockData[props.startTimeCol] = new Date(startTime + (v * 1000 * 60 / props.scaleWidth)).format("yyyy/MM/dd hh:mm:ss")

      // 如果拉过头，那么就强制让startTime 与 endTime 一致
      // 拉过头是因为 this.actionWidth 方法计算是异步的，而v差不多是直接响应出来的，有时候v值是新的，但是actionWidth还是久的，就导致了没能拦住
      if (actionWidth.value <= 0) {
        props.blockData[props.startTimeCol] = props.blockData[props.endTimeCol]
      }

      // 最小50(props.actionBlockMinWidth)宽度 * scale
      if (actionWidth.value <= props.actionBlockMinWidth) {
        const newDate = new Date(props.blockData[props.endTimeCol]).getTime() - (props.actionBlockMinWidth * 1000 * 60 / props.scaleWidth)
        props.blockData[props.startTimeCol] = new Date(newDate).format("yyyy/MM/dd hh:mm:ss")
      }

      mousePosition.left = v
    }
    //右边移动
    else if (direction == 1) {

      //v右边拉长是增加
      if (mousePosition.right > v) {
        //如果是缩短，那么就可以进行width不为-1的判断了
        if (actionWidth.value <= 0) {
          return
        }
      }
      //分钟赋值后，设置成new Date
      props.blockData[props.endTimeCol] = new Date(endTime + (v * 1000 * 60 / props.scaleWidth)).format("yyyy/MM/dd hh:mm:ss")

      if (actionWidth.value <= 0) {
        props.blockData[props.endTimeCol] = props.blockData[props.startTimeCol]
      }

      // 最小50宽度 * scale
      if (actionWidth.value <= props.actionBlockMinWidth) {
        const newDate = new Date(props.blockData[props.startTimeCol]).getTime() + (props.actionBlockMinWidth * 1000 * 60 / props.scaleWidth)
        props.blockData[props.endTimeCol] = new Date(newDate).format("yyyy/MM/dd hh:mm:ss")
      }

      mousePosition.right = v

    }
  }

  window.onmouseup = () => {

    //执行回调，让回调的地方进行http调用
    emit('moveSideChange', props.blockData)

    wordDom.onmousemove = null
    window.onmouseup = null
  }
}

const box = ref(null)
//鼠标自由拖拽用的点下
const onMouseFreeDown = (e) => {
  // 右键点击的情况下，不触发下列事件
  if (e.button === 2) {
    return
  }

  uniqueId = 0

  //时间块的宽度
  const domWidth = actionWidth.value

  //复制出一个dom 以此为操作坐标
  const copyDom = box.value.cloneNode(true);

  const copyDomLeft = box.value.offsetLeft - scrollLeftRef.value

  copyDom.style.left = copyDomLeft + 'px'

  const lineDomStart = document.createElement('div')

  const lineDomEnd = document.createElement('div')

  // 定位线样式
  const styleStr = `
                    position: absolute;
                    height: 100%;
                    width: 1px;
                    box-sizing: border-box;
                    background-image: linear-gradient(transparent 0%, transparent 50%, rgb(255, 154, 154) 50%);
                    background-size: 1px 8px;
                    background-repeat: repeat-y;
                    background-position: top top;
                    z-index: 1000;
                    top:0;
                   `
  lineDomStart.style = styleStr
  lineDomEnd.style = styleStr

  lineDomStart.style.left = copyDomLeft + 'px'
  lineDomEnd.style.left = copyDomLeft + domWidth + 'px'

  //可滚动区域
  const wordDom = props.actionArea
  emit("onActionBlockDown")

  // 摁下的时候 当前块数据  因为虚拟列表会把这个消化掉 所以需要破绑定一下
  const downBlockData = JSON.parse(JSON.stringify(props.blockData))

  const downRowData = JSON.parse(JSON.stringify(props.rowData))

  const downScrollLeft = scrollLeftRef.value
  const diffX = e.clientX - box.value.offsetLeft

  let upLeft = null

  wordDom.onmousemove = (ee) => {

    // 只有第一次移动的时候才创建虚拟dom
    if (uniqueId === 0) {
      wordDom.appendChild(copyDom)
      copyDom.style.opacity = "0.5"
      //copyDom.style.zIndex = "-1"

      wordDom.appendChild(lineDomStart)
      wordDom.appendChild(lineDomEnd)


      uniqueId++
    }


    const top = ee.clientY - getAbsTop(wordDom) - box.value.clientHeight / 2

    copyDom.style.top = top + 'px'

    if (props.enableDragSide) {
      const left = ee.clientX - diffX

      const domLeft = left - downScrollLeft

      copyDom.style.left = domLeft + 'px'

      // 定位线
      lineDomStart.style.left = domLeft + 'px'

      lineDomEnd.style.left = domLeft + copyDom.offsetWidth + 'px'

      upLeft = domLeft + scrollLeftRef.value
    }
  }

  window.onmouseup = () => {

    const rowData = props.ganttData.find(e => e.id === downRowData.id)
    const blockData = rowData[props.timeBlockCol].find(e => e.id === downBlockData.id)

    if (uniqueId === 0) {
      wordDom.onmousemove = null
      window.onmouseup = null

      // 因为虚拟列表的缘故 window的up事件虽然不至于会被清除  但是 寻常emit/on 事件会失效  所以使用全局的事件总线，全局的emit/on
      myInject.changeEvent({
        blockData,
        rowData
      })
      return
    }

    wordDom.removeChild(copyDom)
    wordDom.removeChild(lineDomStart)
    wordDom.removeChild(lineDomEnd)


    if (upLeft) {
      const newLeft = upLeft * 1000 * 60 / props.scaleWidth
      props.blockData[props.startTimeCol] = new Date(new Date(props.choiceTime[0]).getTime() + newLeft).format("yyyy/MM/dd hh:mm:ss")
      props.blockData[props.endTimeCol] = new Date(new Date(props.blockData[props.startTimeCol]).getTime() + (domWidth * 1000 * 60 / props.scaleWidth)).format("yyyy/MM/dd hh:mm:ss")
    }

    // 因为虚拟列表的缘故 window的up事件虽然不至于会被清除  但是 寻常emit/on 事件会失效  所以使用全局的事件总线，全局的emit/on
    myInject.changeEvent({
      blockData,
      rowData
    })

    wordDom.onmousemove = null
    window.onmouseup = null

  }
}


</script>
<style lang="scss" scoped>
.action-block {
  position: absolute;
  box-sizing: border-box;
  z-index: 3;
  border-radius: 4px;
  font-size: 12px;

  .action-box {
    position: relative;
    height: 100%;
    display: flex;
    justify-content: space-between;

    .action-content {
      flex: 1;
    }

    .action {
      position: absolute;
      box-sizing: border-box;
      cursor: pointer;
      width: 5px;
      opacity: 0;
      background-color: rgba(255, 255, 255, 0.5);
      height: 100%;

      &.left-box {
        left: 0;
        cursor: w-resize;
      }

      &.right-box {
        right: 0;
        cursor: e-resize;
      }

      &:hover {
        opacity: 1;
      }
    }
  }
}
</style>